﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Extensil.Common;
using Extensil.Common.CategoryHandler.Discovery;
using System.Net;
using System.IO;
using Extensil.Processor;
using Extensil.Common.CategoryHandler;

namespace Extensil.Category.Discovery
{
    [Extensil.Common.CategoryAttribute("New Updates", false, true)]
    public partial class DiscoveryInstaller :BaseCategory
    {
        static DiscoveryResultList _discoveryResults;
        static BackgroundWorker bwDiscovery = new BackgroundWorker();
        DiscoveryResultList _filterResults;
        static BackgroundWorker bw = new BackgroundWorker();
        public DiscoveryInstaller()
        {
            InitializeComponent();
            pnlWorkSpace.Visible = false;
            timerDiscovery.Interval = CategorySection.GetConfig().DiscoverySection.ProbeInterval;
        }
        protected override void OnLoad(EventArgs e)
        {
            RunDiscoveryProcess();
        }
        void RunDiscoveryProcess()
        {
            bwDiscovery = new BackgroundWorker();
            bwDiscovery.WorkerReportsProgress = true;
            bwDiscovery.WorkerSupportsCancellation = true;
            bwDiscovery.DoWork += new DoWorkEventHandler(Discover);
            bwDiscovery.ProgressChanged += new ProgressChangedEventHandler(Discover_Event);
            bwDiscovery.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwDiscovery_RunWorkerCompleted);
            bwDiscovery.RunWorkerAsync();
        }

        void bwDiscovery_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(_discoveryResults == null)
            {
                ReportStatus(100, "No updates available.");
                return;
            }
            LoadUpdates(_discoveryResults, true);
        }
        void ShowUpdatesLink()
        {
            try
            {
                CategoryFactory.SetCategoryVisible(typeof(DiscoveryInstaller).Name);
                ((ISuperForm)this.SuperForm).Reload();
            }
            catch(Exception exc)
            {
                ReportStatus(100, exc.Message);
            }
        }
        void Discover(object sender, DoWorkEventArgs e)
        {
            try
            {
                DiscoveryManager dm = new DiscoveryManager(ReportStatus);
                _discoveryResults = dm.Discover();

            }
            catch(Exception exc)
            {
                AlertBox.ShowDialog(exc);
            }
        }
        void Discover_Event(object sender, ProgressChangedEventArgs e)
        {
            ReportStatus(e.ProgressPercentage, e.UserState.ToString());
        }
        public void LoadUpdates(DiscoveryResultList results, bool runPost)
        {
            _filterResults = results;
            DiscoveryResultList filterResults = new DiscoveryResultList();
            DateTime lastUpdate = CategorySection.GetConfig().DiscoverySection.LastUpdate;
            PluginHandlers catHnds = CategorySection.GetConfig().CategoryHandlers;
            PluginHandlers prbHnds = CategorySection.GetConfig().ProbeHandlers;
            foreach(DiscoveryResult dr in results)
            {
                Uri fInfo = new Uri(dr.Link);
                PluginHandler phCat = catHnds.GetPluginHandlerWithPlugName(fInfo.Segments[fInfo.Segments.Length - 1]);
                PluginHandler phPrb = prbHnds.GetPluginHandlerWithPlugName(fInfo.Segments[fInfo.Segments.Length - 1]);
                bool needInstallation = false;
                if(phCat != null)
                {
                    //CategoryHandler exists from this plugin
                    Version ver = new Version(phCat.Version);
                    if(dr.Version.CompareTo(ver) > 0 || dr.ModifiedOn.CompareTo(lastUpdate) > 0)
                        needInstallation = true;
                }
                else if(phPrb != null)
                {
                    //ProbeHandler exists from this plugin
                    Version ver = new Version(phPrb.Version);
                    if(dr.Version.CompareTo(ver) > 0 || dr.ModifiedOn.CompareTo(lastUpdate) > 0)
                        needInstallation = true;
                }
                else
                {
                    // New plugin
                    needInstallation = true;
                }
                if(needInstallation)
                    filterResults.Add(dr.Copy);
            }
            ReportStatus(100, "Discovery completed. " + filterResults.Count.ToString() + " updates available.");
            if(filterResults.Count != 0)
                ShowUpdatesLink();
            LoadDiscovetyList(filterResults, runPost);
            using(ConfigModifier cm = new ConfigModifier())
            {
                cm.LastUpdate = DateTime.Now;
                lblNextDiscovery.Text = "Next discovery will run at " + 
                    DateTime.Now.AddMilliseconds(CategorySection.GetConfig().DiscoverySection.ProbeInterval).ToShortTimeString();
            }
        }
        private void timerDiscovery_Tick(object sender, EventArgs e)
        {
            RunDiscoveryProcess();
        }
        void LoadDiscovetyList(DiscoveryResultList filterResults, bool runPost)
        {
            lblCount.Text = ((filterResults.Count == 0) ? "No" : filterResults.Count.ToString()) + " updates available.";
            pbLoading.Visible = false;
            pnlWorkSpace.Visible = true;
            dgvDiscoverList.SelectionChanged += new EventHandler(dgvDiscoverList_SelectionChanged);
            dgvDiscoverList.CellContentDoubleClick += new DataGridViewCellEventHandler(dgvDiscoverList_CellContentDoubleClick);
            dgvDiscoverList.CellMouseEnter += new DataGridViewCellEventHandler(dgvDiscoverList_CellMouseEnter);
            dgvDiscoverList.CellMouseLeave += new DataGridViewCellEventHandler(dgvDiscoverList_CellMouseLeave);
            dgvDiscoverList.DataError += new DataGridViewDataErrorEventHandler(dgvDiscoverList_DataError);
            if(runPost)
                dgvDiscoverList.DataSourceChanged += new EventHandler(dgvDiscoverList_DataSourceChanged);
            else
                dgvDiscoverList.DataSourceChanged -= new EventHandler(dgvDiscoverList_DataSourceChanged);
            dgvDiscoverList.DataSource = filterResults;
        }

        void dgvDiscoverList_DataSourceChanged(object sender, EventArgs e)
        {
            SetPostBindEvents();
        }

        void dgvDiscoverList_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            ReportProgress(100, e.Exception.Message);
        }
        void dgvDiscoverList_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
        {
            ReportProgress(100, "Ready");
        }

        void dgvDiscoverList_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            if(e.RowIndex >= 0)
                ReportProgress(100, dgvDiscoverList.Rows[e.RowIndex].Cells["Description"].Value.ToString());
        }

        void dgvDiscoverList_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            AlertBox.ShowDialog(dgvDiscoverList.Rows[e.RowIndex].Cells["Description"].Value.ToString(), 
                "Information", AlertBoxButtons.OK);
        }

        void dgvDiscoverList_SelectionChanged(object sender, EventArgs e)
        {
            foreach(DataGridViewRow dr in dgvDiscoverList.Rows)
            {
                ((DataGridViewCheckBoxCell)dr.Cells["Select"]).Value = dr.Selected;
            }
        }

        void SetPostBindEvents()
        {
            if(dgvDiscoverList.Rows.Count > 0)
                dgvDiscoverList.Rows[0].Selected = false;
            else
            {
                pnlWorkSpace.Visible = false;
                return;
            }
            dgvDiscoverList.Columns["Copy"].Visible = false;
            dgvDiscoverList.Columns["AutoUpdate"].Visible = false;
            dgvDiscoverList.Columns["ProbeHandler"].Visible = false;
            dgvDiscoverList.Columns["Link"].Visible = false;
            dgvDiscoverList.Columns["Description"].Visible = false;
            
            bool hasSelectedRows = false;
            foreach(DataGridViewRow dr in dgvDiscoverList.Rows)
            {
                if((bool)dr.Cells["AutoUpdate"].Value)
                {
                    ((DataGridViewCheckBoxCell)dr.Cells["Select"]).Selected = true;
                    hasSelectedRows = true;
                }
            }
            if(hasSelectedRows)
            {
                ReportStatus(100, "Installing auto-upgrades.");
                RunInstallationProcess();
            }
        }

        private void btnInstall_Click(object sender, EventArgs e)
        {
            if(dgvDiscoverList.SelectedRows.Count == 0)
            {
                AlertBox.ShowDialog("Please select an item to install.");
                return;
            }
            RunInstallationProcess();
            
        }
        void RunInstallationProcess()
        {
            ReportStatus(100, "In RunInstallationProcess ");
            bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(Install);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            bw.RunWorkerAsync(dgvDiscoverList.Rows);
            pnlWorkSpace.Enabled = false;
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ReportStatus(100, "- bw_RunWorkerCompleted ");
            ReportStatus(100, "Installation completed successfully.");
            ((ISuperForm)this.SuperForm).Reload();
            LoadUpdates(_filterResults, false);
            pnlWorkSpace.Enabled = true;
        }

        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ReportStatus(e.ProgressPercentage, e.UserState.ToString());
        }
        public void ReportStatus(int progress, string message)
        {
            base.ReportProgress(progress, message);
        }
        void Install(object sender, DoWorkEventArgs e)
        {
            DataGridViewRowCollection drList = (DataGridViewRowCollection)e.Argument;
            Dictionary<string, InstallResult> instResults = new Dictionary<string, InstallResult>();
            foreach(DataGridViewRow dr in drList)
            {
                if(((DataGridViewCheckBoxCell)dr.Cells["Select"]).Selected)
                {
                    instResults.Add(
                        dr.Cells["Link"].Value.ToString(),
                        Install((BaseProbeHandler)dr.Cells["ProbeHandler"].Value, 
                            dr.Cells["Link"].Value.ToString())
                            );
                }
            }
            string message = "";
            foreach(string url in instResults.Keys)
            {
                if(!instResults[url].IsSuccessFull)
                {
                    if(String.IsNullOrEmpty(message.Trim()))
                        message = "Some of the plugins could not be installed properly.";
                    message += "\r\n- Plugin source: " + url;
                    foreach(Exception exc in instResults[url])
                        message += "\r\n\t" + exc.Message;
                }
            }
            if(!String.IsNullOrEmpty(message.Trim()))
                AlertBox.ShowDialog(message);
        }
        public InstallResult Install(BaseProbeHandler probeHandler, string url)
        {
            try
            {
                ReportStatus(10, "Installation in progress. Downloading " + url + ".");
                string fileName = probeHandler.DownloadPlugin(url);
                ReportStatus(100, "Installation in progress. Installing " + fileName + ".");
                PluginManager pm = new PluginManager(fileName, ReportStatus);
                InstallResult res = pm.Install();
                if(res.IsSuccessFull)
                    ReportStatus(100, "Installation completed for " + fileName + ".");
                File.Delete(fileName);
                return res;
            }
            catch(Exception exc)
            {
                ReportStatus(100, "Error: " + exc.Message);
                return InstallResult.Create(exc);
            }
        }
        public override BaseSetting Setting
        {
            get
            {
                return new DiscoverySetting();
            }
        }

        private void pnlWorkSpace_EnabledChanged(object sender, EventArgs e)
        {
            pictureBox1.Visible = !pnlWorkSpace.Enabled;
        }

        private void btnDiscover_Click(object sender, EventArgs e)
        {
            RunDiscoveryProcess();
        }

    }
}
